Skip to contentMethod: getComparingParamTypesForVarArgsMethod(Class[], int)
1: /*
2: * Copyright (c) 1997, 2022 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: * Copyright 2004 The Apache Software Foundation
5: *
6: * Licensed under the Apache License, Version 2.0 (the "License");
7: * you may not use this file except in compliance with the License.
8: * You may obtain a copy of the License at
9: *
10: * http://www.apache.org/licenses/LICENSE-2.0
11: *
12: * Unless required by applicable law or agreed to in writing, software
13: * distributed under the License is distributed on an "AS IS" BASIS,
14: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15: * See the License for the specific language governing permissions and
16: * limitations under the License.
17: */
18:
19: package jakarta.el;
20:
21: import java.lang.reflect.AccessibleObject;
22: import java.lang.reflect.Array;
23: import java.lang.reflect.Constructor;
24: import java.lang.reflect.InvocationTargetException;
25: import java.lang.reflect.Method;
26: import java.lang.reflect.Modifier;
27: import java.text.MessageFormat;
28: import java.util.ArrayList;
29: import java.util.HashMap;
30: import java.util.Iterator;
31: import java.util.List;
32: import java.util.Locale;
33: import java.util.Map;
34: import java.util.MissingResourceException;
35: import java.util.ResourceBundle;
36:
37: /**
38: * Utility methods for this portion of the Jakarta Expression Language implementation
39: *
40: * <p>
41: * Methods on this class use a Map instance stored in ThreadLocal storage to minimize the performance impact on
42: * operations that take place multiple times on a single Thread. The keys and values of the Map are implementation
43: * private.
44: *
45: * @author edburns
46: * @author Kin-man Chung
47: * @author Dongbin Nie
48: */
49: class ELUtil {
50:
51: /**
52: * This class may not be constructed.
53: */
54: private ELUtil() {
55: }
56:
57: /**
58: * <p>
59: * The <code>ThreadLocal</code> variable used to record the <code>jakarta.faces.context.FacesContext</code> instance for
60: * each processing thread.
61: * </p>
62: */
63: private static ThreadLocal<Map<String, ResourceBundle>> instance = new ThreadLocal<>() {
64: @Override
65: protected Map<String, ResourceBundle> initialValue() {
66: return (null);
67: }
68: };
69:
70: /**
71: * @return a Map stored in ThreadLocal storage. This may be used by methods of this class to minimize the performance
72: * impact for operations that may take place multiple times on a given Thread instance.
73: */
74: private static Map<String, ResourceBundle> getCurrentInstance() {
75: Map<String, ResourceBundle> result = instance.get();
76: if (result == null) {
77: result = new HashMap<>();
78: setCurrentInstance(result);
79: }
80:
81: return result;
82:
83: }
84:
85: /**
86: * Replace the Map with the argument context.
87: *
88: * @param context the Map to be stored in ThreadLocal storage.
89: */
90: private static void setCurrentInstance(Map<String, ResourceBundle> context) {
91: instance.set(context);
92: }
93:
94: /**
95: * Convenience method, calls through to getExceptionMessageString(ELContext,java.lang.String,Object []).
96: *
97: * @param context the ELContext from which the Locale for this message is extracted.
98: * @param messageId the messageId String in the ResourceBundle
99: *
100: * @return a localized String for the argument messageId
101: */
102: public static String getExceptionMessageString(ELContext context, String messageId) {
103: return getExceptionMessageString(context, messageId, null);
104: }
105:
106: /*
107: * <p>Return a Localized message String suitable for use as an Exception message. Examine the argument
108: * <code>context</code> for a <code>Locale</code>. If not present, use <code>Locale.getDefault()</code>. Load the
109: * <code>ResourceBundle</code> "jakarta.el.Messages" using that locale. Get the message string for argument
110: * <code>messageId</code>. If not found return "Missing Resource in Jakarta Expression Language implementation ??? messageId ???" with messageId
111: * substituted with the runtime value of argument <code>messageId</code>. If found, and argument <code>params</code> is
112: * non-null, format the message using the params. If formatting fails, return a sensible message including the
113: * <code>messageId</code>. If argument <code>params</code> is <code>null</code>, skip formatting and return the message
114: * directly, otherwise return the formatted message.</p>
115: *
116: * @param context the ELContext from which the Locale for this message is extracted.
117: *
118: * @param messageId the messageId String in the ResourceBundle
119: *
120: * @param params parameters to the message
121: *
122: * @return a localized String for the argument messageId
123: */
124: public static String getExceptionMessageString(ELContext context, String messageId, Object[] params) {
125: String result = "";
126: Locale locale = null;
127:
128: if (null == context || null == messageId) {
129: return result;
130: }
131:
132: if (null == (locale = context.getLocale())) {
133: locale = Locale.getDefault();
134: }
135:
136: if (locale != null) {
137: Map<String, ResourceBundle> threadMap = getCurrentInstance();
138: ResourceBundle resourceBundle = null;
139: if (null == (resourceBundle = threadMap.get(locale.toString()))) {
140: resourceBundle = ResourceBundle.getBundle("jakarta.el.PrivateMessages", locale);
141: threadMap.put(locale.toString(), resourceBundle);
142: }
143:
144: if (null != resourceBundle) {
145: try {
146: result = resourceBundle.getString(messageId);
147: if (null != params) {
148: result = MessageFormat.format(result, params);
149: }
150: } catch (IllegalArgumentException iae) {
151: result = "Can't get localized message: parameters to message appear to be incorrect. Message to format: " + messageId;
152: } catch (MissingResourceException mre) {
153: result = "Missing Resource in Jakarta Expression Language implementation: ???" + messageId + "???";
154: } catch (Exception e) {
155: result = "Exception resolving message in Jakarta Expression Language implementation: ???" + messageId + "???";
156: }
157: }
158: }
159:
160: return result;
161: }
162:
163: static Constructor<?> findConstructor(Class<?> klass, Class<?>[] paramTypes, Object[] params) {
164: String methodName = "<init>";
165:
166: if (klass == null) {
167: throw new MethodNotFoundException("Method not found: " + klass + "." + methodName + "(" + paramString(paramTypes) + ")");
168: }
169:
170: if (paramTypes == null) {
171: paramTypes = getTypesFromValues(params);
172: }
173:
174: Constructor<?>[] constructors = klass.getConstructors();
175:
176: List<Wrapper> wrappers = Wrapper.wrap(constructors);
177:
178: Wrapper result = findWrapper(klass, wrappers, methodName, paramTypes, params);
179:
180: if (result == null) {
181: return null;
182: }
183:
184: return getConstructor(klass, (Constructor<?>) result.unWrap());
185: }
186:
187: static Object invokeConstructor(ELContext context, Constructor<?> constructor, Object[] params) {
188: Object[] parameters = buildParameters(context, constructor.getParameterTypes(), constructor.isVarArgs(), params);
189: try {
190: return constructor.newInstance(parameters);
191: } catch (IllegalAccessException iae) {
192: throw new ELException(iae);
193: } catch (IllegalArgumentException iae) {
194: throw new ELException(iae);
195: } catch (InvocationTargetException ite) {
196: throw new ELException(ite.getCause());
197: } catch (InstantiationException ie) {
198: throw new ELException(ie.getCause());
199: }
200: }
201:
202: static Method findMethod(Class<?> klass, Object base, String methodName, Class<?>[] paramTypes, Object[] params, boolean staticOnly) {
203: Method method = findMethod(klass, base, methodName, paramTypes, params);
204: if (staticOnly && !Modifier.isStatic(method.getModifiers())) {
205: throw new MethodNotFoundException("Method " + methodName + "for class " + klass + " not found or accessible");
206: }
207:
208: return method;
209: }
210:
211: static Object invokeMethod(ELContext context, Method method, Object base, Object[] params) {
212:
213: Object[] parameters = buildParameters(context, method.getParameterTypes(), method.isVarArgs(), params);
214: try {
215: return method.invoke(base, parameters);
216: } catch (IllegalAccessException iae) {
217: throw new ELException(iae);
218: } catch (IllegalArgumentException iae) {
219: throw new ELException(iae);
220: } catch (InvocationTargetException ite) {
221: throw new ELException(ite.getCause());
222: }
223: }
224:
225: static Method findMethod(Class<?> clazz, Object base, String methodName, Class<?>[] paramTypes, Object[] paramValues) {
226: if (clazz == null || methodName == null) {
227: throw new MethodNotFoundException("Method not found: " + clazz + "." + methodName + "(" + paramString(paramTypes) + ")");
228: }
229:
230: if (paramTypes == null) {
231: paramTypes = getTypesFromValues(paramValues);
232: }
233:
234: Method[] methods = clazz.getMethods();
235:
236: List<Wrapper> wrappers = Wrapper.wrap(methods, methodName);
237:
238: Wrapper result = findWrapper(clazz, wrappers, methodName, paramTypes, paramValues);
239:
240: if (result == null) {
241: return null;
242: }
243:
244: return getMethod(clazz, base, (Method) result.unWrap());
245: }
246:
247: @SuppressWarnings("null")
248: private static Wrapper findWrapper(Class<?> clazz, List<Wrapper> wrappers, String name, Class<?>[] paramTypes, Object[] paramValues) {
249: List<Wrapper> assignableCandidates = new ArrayList<>();
250: List<Wrapper> coercibleCandidates = new ArrayList<>();
251: List<Wrapper> varArgsCandidates = new ArrayList<>();
252:
253: int paramCount;
254: if (paramTypes == null) {
255: paramCount = 0;
256: } else {
257: paramCount = paramTypes.length;
258: }
259:
260: for (Wrapper w : wrappers) {
261: Class<?>[] mParamTypes = w.getParameterTypes();
262: int mParamCount;
263: if (mParamTypes == null) {
264: mParamCount = 0;
265: } else {
266: mParamCount = mParamTypes.length;
267: }
268:
269: // Check the number of parameters
270: if (!(paramCount == mParamCount || (w.isVarArgs() && paramCount >= mParamCount - 1))) {
271: // Method has wrong number of parameters
272: continue;
273: }
274:
275: // Check the parameters match
276: boolean assignable = false;
277: boolean coercible = false;
278: boolean varArgs = false;
279: boolean noMatch = false;
280: for (int i = 0; i < mParamCount; i++) {
281: if (i == (mParamCount - 1) && w.isVarArgs()) {
282: varArgs = true;
283: // exact var array type match
284: if (mParamCount == paramCount) {
285: if (mParamTypes[i] == paramTypes[i]) {
286: continue;
287: }
288: }
289:
290: // unwrap the array's component type
291: Class<?> varType = mParamTypes[i].getComponentType();
292: for (int j = i; j < paramCount; j++) {
293: if (!isAssignableFrom(paramTypes[j], varType)
294: && !(paramValues != null && j < paramValues.length && isCoercibleFrom(paramValues[j], varType))) {
295: noMatch = true;
296: break;
297: }
298: }
299: } else if (mParamTypes[i].equals(paramTypes[i])) {
300: } else if (isAssignableFrom(paramTypes[i], mParamTypes[i])) {
301: assignable = true;
302: } else {
303: if (paramValues == null || i >= paramValues.length) {
304: noMatch = true;
305: break;
306: } else {
307: if (isCoercibleFrom(paramValues[i], mParamTypes[i])) {
308: coercible = true;
309: } else {
310: noMatch = true;
311: break;
312: }
313: }
314: }
315: }
316: if (noMatch) {
317: continue;
318: }
319:
320: if (varArgs) {
321: varArgsCandidates.add(w);
322: } else if (coercible) {
323: coercibleCandidates.add(w);
324: } else if (assignable) {
325: assignableCandidates.add(w);
326: } else {
327: // If a method is found where every parameter matches exactly,
328: // return it
329: return w;
330: }
331:
332: }
333:
334: String errorMsg = "Unable to find unambiguous method: " + clazz + "." + name + "(" + paramString(paramTypes) + ")";
335: if (!assignableCandidates.isEmpty()) {
336: return findMostSpecificWrapper(assignableCandidates, paramTypes, false, errorMsg);
337: } else if (!coercibleCandidates.isEmpty()) {
338: return findMostSpecificWrapper(coercibleCandidates, paramTypes, true, errorMsg);
339: } else if (!varArgsCandidates.isEmpty()) {
340: return findMostSpecificWrapper(varArgsCandidates, paramTypes, true, errorMsg);
341: } else {
342: throw new MethodNotFoundException("Method not found: " + clazz + "." + name + "(" + paramString(paramTypes) + ")");
343: }
344: }
345:
346: private static Wrapper findMostSpecificWrapper(List<Wrapper> candidates, Class<?>[] matchingTypes, boolean elSpecific, String errorMsg) {
347: List<Wrapper> ambiguouses = new ArrayList<>();
348: for (Wrapper candidate : candidates) {
349: boolean lessSpecific = false;
350:
351: Iterator<Wrapper> it = ambiguouses.iterator();
352: while (it.hasNext()) {
353: int result = isMoreSpecific(candidate, it.next(), matchingTypes, elSpecific);
354: if (result == 1) {
355: it.remove();
356: } else if (result == -1) {
357: lessSpecific = true;
358: }
359: }
360:
361: if (!lessSpecific) {
362: ambiguouses.add(candidate);
363: }
364: }
365:
366: if (ambiguouses.size() > 1) {
367: throw new MethodNotFoundException(errorMsg);
368: }
369:
370: return ambiguouses.get(0);
371: }
372:
373: private static int isMoreSpecific(Wrapper wrapper1, Wrapper wrapper2, Class<?>[] matchingTypes, boolean elSpecific) {
374: Class<?>[] paramTypes1 = wrapper1.getParameterTypes();
375: Class<?>[] paramTypes2 = wrapper2.getParameterTypes();
376:
377: if (wrapper1.isVarArgs()) {
378: // JLS8 15.12.2.5 Choosing the Most Specific Method
379: int length = Math.max(Math.max(paramTypes1.length, paramTypes2.length), matchingTypes.length);
380: paramTypes1 = getComparingParamTypesForVarArgsMethod(paramTypes1, length);
381: paramTypes2 = getComparingParamTypesForVarArgsMethod(paramTypes2, length);
382:
383: if (length > matchingTypes.length) {
384: Class<?>[] matchingTypes2 = new Class<?>[length];
385: System.arraycopy(matchingTypes, 0, matchingTypes2, 0, matchingTypes.length);
386: matchingTypes = matchingTypes2;
387: }
388: }
389:
390: int result = 0;
391: for (int i = 0; i < paramTypes1.length; i++) {
392: if (paramTypes1[i] != paramTypes2[i]) {
393: int r2 = isMoreSpecific(paramTypes1[i], paramTypes2[i], matchingTypes[i], elSpecific);
394: if (r2 == 1) {
395: if (result == -1) {
396: return 0;
397: }
398: result = 1;
399: } else if (r2 == -1) {
400: if (result == 1) {
401: return 0;
402: }
403: result = -1;
404: } else {
405: return 0;
406: }
407: }
408: }
409:
410: if (result == 0) {
411: // The nature of bridge methods is such that it actually
412: // doesn't matter which one we pick as long as we pick
413: // one. That said, pick the 'right' one (the non-bridge
414: // one) anyway.
415: result = Boolean.compare(wrapper1.isBridge(), wrapper2.isBridge());
416: }
417:
418: return result;
419: }
420:
421: private static int isMoreSpecific(Class<?> type1, Class<?> type2, Class<?> matchingType, boolean elSpecific) {
422: type1 = getBoxingTypeIfPrimitive(type1);
423: type2 = getBoxingTypeIfPrimitive(type2);
424: if (type2.isAssignableFrom(type1)) {
425: return 1;
426: } else if (type1.isAssignableFrom(type2)) {
427: return -1;
428: } else {
429: if (elSpecific) {
430: /*
431: * Number will be treated as more specific
432: *
433: * ASTInteger only return Long or BigInteger, no Byte / Short / Integer. ASTFloatingPoint also.
434: *
435: */
436: if (matchingType != null && Number.class.isAssignableFrom(matchingType)) {
437: boolean b1 = Number.class.isAssignableFrom(type1) || type1.isPrimitive();
438: boolean b2 = Number.class.isAssignableFrom(type2) || type2.isPrimitive();
439: if (b1 && !b2) {
440: return 1;
441: } else if (b2 && !b1) {
442: return -1;
443: } else {
444: return 0;
445: }
446: }
447:
448: return 0;
449: } else {
450: return 0;
451: }
452: }
453: }
454:
455: private static Class<?> getBoxingTypeIfPrimitive(Class<?> clazz) {
456: if (clazz.isPrimitive()) {
457: if (clazz == Boolean.TYPE) {
458: return Boolean.class;
459: }
460: if (clazz == Character.TYPE) {
461: return Character.class;
462: }
463: if (clazz == Byte.TYPE) {
464: return Byte.class;
465: }
466: if (clazz == Short.TYPE) {
467: return Short.class;
468: }
469: if (clazz == Integer.TYPE) {
470: return Integer.class;
471: }
472: if (clazz == Long.TYPE) {
473: return Long.class;
474: }
475: if (clazz == Float.TYPE) {
476: return Float.class;
477: }
478:
479: return Double.class;
480: } else {
481: return clazz;
482: }
483: }
484:
485: private static Class<?>[] getComparingParamTypesForVarArgsMethod(Class<?>[] paramTypes, int length) {
486: Class<?>[] result = new Class<?>[length];
487: System.arraycopy(paramTypes, 0, result, 0, paramTypes.length - 1);
488: Class<?> type = paramTypes[paramTypes.length - 1].getComponentType();
489:• for (int i = paramTypes.length - 1; i < length; i++) {
490: result[i] = type;
491: }
492:
493: return result;
494: }
495:
496: private static final String paramString(Class<?>[] types) {
497: if (types != null) {
498: StringBuilder sb = new StringBuilder();
499: for (int i = 0; i < types.length; i++) {
500: if (types[i] == null) {
501: sb.append("null, ");
502: } else {
503: sb.append(types[i].getName()).append(", ");
504: }
505: }
506: if (sb.length() > 2) {
507: sb.setLength(sb.length() - 2);
508: }
509: return sb.toString();
510: }
511: return null;
512: }
513:
514: static boolean isAssignableFrom(Class<?> src, Class<?> target) {
515: // src will always be an object
516: // Short-cut. null is always assignable to an object and in Jakarta Expression Language null
517: // can always be coerced to a valid value for a primitive
518: if (src == null) {
519: return true;
520: }
521:
522: target = getBoxingTypeIfPrimitive(target);
523:
524: return target.isAssignableFrom(src);
525: }
526:
527: private static boolean isCoercibleFrom(Object src, Class<?> target) {
528: // TODO: This isn't pretty but it works. Significant refactoring would
529: // be required to avoid the exception.
530: try {
531: ELManager.getExpressionFactory().coerceToType(src, target);
532: } catch (Exception e) {
533: return false;
534: }
535:
536: return true;
537: }
538:
539: private static Class<?>[] getTypesFromValues(Object[] values) {
540: if (values == null) {
541: return null;
542: }
543:
544: Class<?> result[] = new Class<?>[values.length];
545: for (int i = 0; i < values.length; i++) {
546: if (values[i] == null) {
547: result[i] = null;
548: } else {
549: result[i] = values[i].getClass();
550: }
551: }
552:
553: return result;
554: }
555:
556: /*
557: * Get a public method form a public class or interface of a given method. Note that if a PropertyDescriptor is obtained
558: * for a non-public class that implements a public interface, the read/write methods will be for the class, and
559: * therefore inaccessible. To correct this, a version of the same method must be found in a superclass or interface.
560: */
561: static Method getMethod(Class<?> type, Object base, Method m) {
562: // If base is null, method MUST be static
563: // If base is non-null, method may be static or non-static
564: if (m == null ||
565: (Modifier.isPublic(type.getModifiers()) &&
566: (canAccess(base, m) || base != null && canAccess(null, m)))) {
567: return m;
568: }
569: Class<?>[] inf = type.getInterfaces();
570: Method mp = null;
571: for (int i = 0; i < inf.length; i++) {
572: try {
573: mp = inf[i].getMethod(m.getName(), m.getParameterTypes());
574: mp = getMethod(mp.getDeclaringClass(), base, mp);
575: if (mp != null) {
576: return mp;
577: }
578: } catch (NoSuchMethodException e) {
579: // Ignore
580: }
581: }
582: Class<?> sup = type.getSuperclass();
583: if (sup != null) {
584: try {
585: mp = sup.getMethod(m.getName(), m.getParameterTypes());
586: mp = getMethod(mp.getDeclaringClass(), base, mp);
587: if (mp != null) {
588: return mp;
589: }
590: } catch (NoSuchMethodException e) {
591: // Ignore
592: }
593: }
594: return null;
595: }
596:
597: static Constructor<?> getConstructor(Class<?> type, Constructor<?> c) {
598: if (c == null || Modifier.isPublic(type.getModifiers())) {
599: return c;
600: }
601: Constructor<?> cp = null;
602: Class<?> sup = type.getSuperclass();
603: if (sup != null) {
604: try {
605: cp = sup.getConstructor(c.getParameterTypes());
606: cp = getConstructor(cp.getDeclaringClass(), cp);
607: if (cp != null) {
608: return cp;
609: }
610: } catch (NoSuchMethodException e) {
611: // Ignore
612: }
613: }
614: return null;
615: }
616:
617:
618: static boolean canAccess(Object base, AccessibleObject accessibleObject) {
619: try {
620: return accessibleObject.canAccess(base);
621: } catch (IllegalArgumentException iae) {
622: return false;
623: }
624: }
625:
626:
627: @SuppressWarnings("null") // params cannot be null when used
628: static Object[] buildParameters(ELContext context, Class<?>[] parameterTypes, boolean isVarArgs, Object[] params) {
629: Object[] parameters = null;
630: if (parameterTypes.length > 0) {
631: parameters = new Object[parameterTypes.length];
632: int paramCount = params == null ? 0 : params.length;
633: if (isVarArgs) {
634: int varArgIndex = parameterTypes.length - 1;
635: // First argCount-1 parameters are standard
636: for (int i = 0; (i < varArgIndex && i < paramCount); i++) {
637: parameters[i] = context.convertToType(params[i], parameterTypes[i]);
638: }
639: // Last parameter is the varargs
640: if (parameterTypes.length == paramCount && params[varArgIndex] != null &&
641: parameterTypes[varArgIndex] == params[varArgIndex].getClass()) {
642: parameters[varArgIndex] = params[varArgIndex];
643: } else {
644: Class<?> varArgClass = parameterTypes[varArgIndex].getComponentType();
645: final Object varargs = Array.newInstance(varArgClass, (paramCount - varArgIndex));
646: for (int i = (varArgIndex); i < paramCount; i++) {
647: Array.set(varargs, i - varArgIndex, context.convertToType(params[i], varArgClass));
648: }
649: parameters[varArgIndex] = varargs;
650: }
651: } else {
652: for (int i = 0; i < parameterTypes.length && i < paramCount; i++) {
653: parameters[i] = context.convertToType(params[i], parameterTypes[i]);
654: }
655: }
656: }
657: return parameters;
658: }
659:
660: private abstract static class Wrapper {
661:
662: public static List<Wrapper> wrap(Method[] methods, String name) {
663: List<Wrapper> result = new ArrayList<>();
664: for (Method method : methods) {
665: if (method.getName().equals(name)) {
666: result.add(new MethodWrapper(method));
667: }
668: }
669: return result;
670: }
671:
672: public static List<Wrapper> wrap(Constructor<?>[] constructors) {
673: List<Wrapper> result = new ArrayList<>();
674: for (Constructor<?> constructor : constructors) {
675: result.add(new ConstructorWrapper(constructor));
676: }
677: return result;
678: }
679:
680: public abstract Object unWrap();
681:
682: public abstract Class<?>[] getParameterTypes();
683:
684: public abstract boolean isVarArgs();
685:
686: public abstract boolean isBridge();
687: }
688:
689: private static class MethodWrapper extends Wrapper {
690: private final Method m;
691:
692: public MethodWrapper(Method m) {
693: this.m = m;
694: }
695:
696: @Override
697: public Object unWrap() {
698: return m;
699: }
700:
701: @Override
702: public Class<?>[] getParameterTypes() {
703: return m.getParameterTypes();
704: }
705:
706: @Override
707: public boolean isVarArgs() {
708: return m.isVarArgs();
709: }
710:
711: @Override
712: public boolean isBridge() {
713: return m.isBridge();
714: }
715: }
716:
717: private static class ConstructorWrapper extends Wrapper {
718: private final Constructor<?> c;
719:
720: public ConstructorWrapper(Constructor<?> c) {
721: this.c = c;
722: }
723:
724: @Override
725: public Object unWrap() {
726: return c;
727: }
728:
729: @Override
730: public Class<?>[] getParameterTypes() {
731: return c.getParameterTypes();
732: }
733:
734: @Override
735: public boolean isVarArgs() {
736: return c.isVarArgs();
737: }
738:
739: @Override
740: public boolean isBridge() {
741: return false;
742: }
743: }
744: }